package com.ruyiadmin.springboot.controller.core;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.ruyiadmin.springboot.common.annotations.core.AllowAnonymous;
import com.ruyiadmin.springboot.common.beans.system.JwtSettings;
import com.ruyiadmin.springboot.common.core.business.entities.JwtSecurityAuthentication;
import com.ruyiadmin.springboot.common.core.business.entities.JwtSecurityToken;
import com.ruyiadmin.springboot.common.core.system.entities.ActionResult;
import com.ruyiadmin.springboot.common.exceptions.RuYiAdminCustomException;
import com.ruyiadmin.springboot.common.components.core.RuYiRedisComponent;
import com.ruyiadmin.springboot.common.utils.core.RuYiHashUtil;
import com.ruyiadmin.springboot.common.utils.system.RuYiJwtTokenUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.UUID;

/**
 * <p>
 * 系统Jwt授权服务 前端控制器
 * </p>
 *
 * @author RuYiAdmin
 * @since 2022-07-14
 */
@RestController
@RequestMapping("/JwtSecurityAuthentication")
@Api(tags = "系统Jwt授权服务")
@RequiredArgsConstructor
@EnableConfigurationProperties({JwtSettings.class})
public class JwtSecurityAuthenticationController {

    //region 服务私有属性

    private final JwtSettings jwtSettings;
    private final RuYiRedisComponent redisUtils;

    //endregion

    //region Jwt获取盐服务

    @GetMapping("/Get")
    @ApiOperation(value = "Jwt获取盐服务")
    @AllowAnonymous
    public ActionResult getSalt(String userName) throws RuYiAdminCustomException, BlockException {
        Entry ignored = SphU.entry("QueryJwtSalt");
        if (StringUtils.isEmpty(userName)) {
            throw new RuYiAdminCustomException("user name can not be null");
        }
        if (userName.equals(jwtSettings.getDefaultUser())) {
            String salt = UUID.randomUUID().toString();
            String entryStr = RuYiHashUtil.SHA512(jwtSettings.getDefaultPassword() + salt);
            this.redisUtils.set(salt, entryStr, jwtSettings.getSaltExpiration());
            return ActionResult.success(salt);
        }
        throw new RuYiAdminCustomException("no content");
    }

    //endregion

    //region Jwt身份认证接口

    @PostMapping("/Post")
    @ApiOperation(value = "Jwt身份认证接口")
    @AllowAnonymous
    public ActionResult getJwtSecurityToken(@RequestBody @Valid JwtSecurityAuthentication authentication)
            throws RuYiAdminCustomException {
        String entryStr = null;
        Object value = this.redisUtils.get(authentication.getSalt());
        entryStr = value == null ? StringUtils.EMPTY : value.toString();
        if (StringUtils.isEmpty(entryStr)) {
            throw new RuYiAdminCustomException("salt is invalid");
        }
        if (authentication.getUserName().equals(this.jwtSettings.getDefaultUser())
                && authentication.getPassword().equalsIgnoreCase(entryStr)) {
            this.redisUtils.del(authentication.getSalt());
            String tokenId = UUID.randomUUID().toString();
            String token = RuYiJwtTokenUtil.createJwtSecurityToken(this.jwtSettings, tokenId);
            //设置RefreshToken有效期
            this.redisUtils.set(tokenId, tokenId, (long) 12 * 3 * this.jwtSettings.getTokenExpiration() * 60);
            return ActionResult.success(new JwtSecurityToken(token, tokenId));
        }
        throw new RuYiAdminCustomException("not found");
    }

    //endregion

    //region 刷新JwtToken

    @GetMapping("/RefreshToken")
    @ApiOperation(value = "刷新JwtToken")
    @AllowAnonymous
    public ActionResult refreshJwtToken(@RequestHeader("Authorization") String accessToken,
                                        @RequestHeader("RefreshToken") String refreshToken)
            throws RuYiAdminCustomException {
        try {
            RuYiJwtTokenUtil.verifyToken(this.jwtSettings, accessToken.replace("Bearer ", ""));
        } catch (TokenExpiredException e) {
            Object value = this.redisUtils.get(refreshToken);
            String rtValue = value == null ? StringUtils.EMPTY : value.toString();
            if (!StringUtils.isEmpty(rtValue) && rtValue.equals(refreshToken)) {
                //删除旧RefreshToken
                this.redisUtils.del(refreshToken);
                String tokenId = UUID.randomUUID().toString();
                String token = RuYiJwtTokenUtil.createJwtSecurityToken(this.jwtSettings, tokenId);
                //设置RefreshToken有效期
                this.redisUtils.set(tokenId, tokenId, (long) 12 * 3 * this.jwtSettings.getTokenExpiration() * 60);
                return ActionResult.success(new JwtSecurityToken(token, tokenId));
            }
        }
        throw new RuYiAdminCustomException("forbid");
    }

    //endregion

}
